﻿/* AgileFx Version 1.0
 * An open-source framework for rapid development of applications and services using Microsoft.net
 * Developed by: AgileHead
 * Website: www.agilefx.org
 * This component is licensed under the terms of the Apache 2.0 License.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Mvc.Html;

using AgileFx.EF;
using System.Linq.Expressions;

namespace AgileFx.MVC
{
    public static class HtmlElements
    {
        //---- Option List ---- //
        public static string OptionList<T>(IEnumerable<T> items,
            Func<T, object> displayMember, Func<T, object> valueMember,
            string selectedValue)
        {
            return OptionList(items, null, displayMember, valueMember, selectedValue);
        }

        public static string OptionList<T>(IEnumerable<T> items, string emptyOptionLabel,
            Func<T, object> displayMember, Func<T, object> valueMember,
            string selectedValue)
        {
            Func<string, string, bool, string> optionText = (t, v, b) =>
                string.Format("<option value=\"{1}\"{2}>{0}</option>", t, v, b ? " selected=\"selected\"" : "");

            StringBuilder html = new StringBuilder();
            if (!emptyOptionLabel.Empty())
                html.Append(optionText(emptyOptionLabel, "", (String.IsNullOrEmpty(selectedValue) ? true : false)));

            foreach (var item in items)
                html.Append(optionText(displayMember(item).ToString(), valueMember(item).ToString(),
                    valueMember(item).ToString() == selectedValue));

            return html.ToString();
        }

        public static string OptionList<T>(IEnumerable<T> items, string emptyOptionLabel,
            Func<T, object> displayMember, Func<T, object> valueMember,
            Func<T, bool> isSelected)
        {
            Func<string, string, bool, string> optionText = (t, v, b) =>
                string.Format("<option value=\"{1}\"{2}>{0}</option>", t, v, b ? " selected=\"selected\"" : "");

            StringBuilder html = new StringBuilder();
            if (!emptyOptionLabel.Empty())
                html.Append(optionText(emptyOptionLabel, "", false));

            foreach (var item in items)
                html.Append(optionText(displayMember(item).ToString(), valueMember(item).ToString(),
                    isSelected(item)));

            return html.ToString();
        }

        public static IEnumerable<SelectListItem> GetSelectItems<T>(IEnumerable<T> items, Func<T, object> valueSelector,
            Func<T, object> displaySelector)
        {
            return items.Select(x =>
                new SelectListItem
                {
                    Text = displaySelector(x).ToString(),
                    Value = valueSelector(x).ToString()
                });
        } 

        public static IEnumerable<SelectListItem> GetSelectItems<T>(IEnumerable<T> items, Func<T, object> valueSelector,
            Func<T, object> displaySelector, object selectedValue)
        {
            return items.Select(x =>
                new SelectListItem
                {
                    Text = displaySelector(x).ToString(),
                    Value = valueSelector(x).ToString(),
                    Selected = ((selectedValue ?? "").ToString() == (valueSelector(x) ?? "").ToString())
                });
        }

        public static IEnumerable<SelectListItem> GetSelectItems<T>(IEnumerable<T> items, Func<T, object> valueSelector,
            Func<T, object> displaySelector, Func<T, bool> isSelected)
        {
            return items.Select(x =>
                new SelectListItem
                {
                    Text = displaySelector(x).ToString(),
                    Value = valueSelector(x).ToString(),
                    Selected = isSelected(x)
                });
        }

        public static string CheckBoxList(this HtmlHelper htmlHelper, string name, List<CheckBoxListInfo> listInfo)
        {
            return htmlHelper.CheckBoxList(name, listInfo, ((IDictionary<string, object>)null));
        }

        public static string CheckBoxList(this HtmlHelper htmlHelper, string name, List<CheckBoxListInfo> listInfo,

            object htmlAttributes)
        {
            return htmlHelper.CheckBoxList(name, listInfo, ((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes)));
        }

        public static string Password(this HtmlHelper htmlHelper, string name, Validation validationInfo)
        {
            return htmlHelper.Password(name, null, GetValidationAttributes(validationInfo));
        }

        public static string Password(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes, Validation validationInfo)
        {
            return htmlHelper.Password(name, value, GetValidationAttributes(htmlAttributes, validationInfo));
        }

        public static string TextBox(this HtmlHelper htmlHelper, string name, Validation validationInfo)
        {
            return htmlHelper.TextBox(name, null, GetValidationAttributes(validationInfo));
        }

        public static string TextBox(this HtmlHelper htmlHelper, string name, object value, Validation validationInfo)
        {
            return htmlHelper.TextBox(name, value, GetValidationAttributes(validationInfo));
        }

        public static string TextBox(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes, Validation validationInfo)
        {
            return htmlHelper.TextBox(name, value, GetValidationAttributes(htmlAttributes, validationInfo));
        }

        public static string TextArea(this HtmlHelper htmlHelper, string name, Validation validationInfo)
        {
            return htmlHelper.TextArea(name, GetValidationAttributes(validationInfo));
        }

        public static string TextArea(this HtmlHelper htmlHelper, string name, object htmlAttributes, Validation validationInfo)
        {
            return htmlHelper.TextArea(name, GetValidationAttributes(htmlAttributes, validationInfo));
        }

        public static string TextArea(this HtmlHelper htmlHelper, string name, string value, Validation validationInfo)
        {
            return htmlHelper.TextArea(name, value, GetValidationAttributes(validationInfo));
        }

        public static string TextArea(this HtmlHelper htmlHelper, string name, string value, object htmlAttributes, Validation validationInfo)
        {
            return htmlHelper.TextArea(name, value, GetValidationAttributes(htmlAttributes, validationInfo));
        }

        public static string DropDownList(this HtmlHelper htmlHelper, string name, string optionLabel, Validation validationInfo)
        {
            return htmlHelper.DropDownList(name, new List<SelectListItem>(), optionLabel, GetValidationAttributes(validationInfo));
        }

        public static string DropDownList(this HtmlHelper htmlHelper, string name, string optionLabel, object htmlAttributes, Validation validationInfo)
        {
            return htmlHelper.DropDownList(name, new List<SelectListItem>(), optionLabel, GetValidationAttributes(htmlAttributes, validationInfo));
        }

        public static string DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, Validation validationInfo)
        {
            return htmlHelper.DropDownList(name, selectList, GetValidationAttributes(validationInfo));
        }

        public static string DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, string optionLabel, Validation validationInfo)
        {
            return htmlHelper.DropDownList(name, selectList, optionLabel, GetValidationAttributes(validationInfo));
        }

        public static string DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, object htmlAttributes, Validation validationInfo)
        {
            return htmlHelper.DropDownList(name, selectList, GetValidationAttributes(htmlAttributes, validationInfo));
        }

        public static string DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, string optionLabel, object htmlAttributes, Validation validationInfo)
        {
            return htmlHelper.DropDownList(name, selectList, optionLabel, GetValidationAttributes(htmlAttributes, validationInfo));
        }

        public static string ListBox(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, Validation validationInfo)
        {
            return htmlHelper.ListBox(name, selectList, GetValidationAttributes(validationInfo));
        }

        public static string ListBox(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, object htmlAttributes, Validation validationInfo)
        {
            return htmlHelper.ListBox(name, selectList, GetValidationAttributes(htmlAttributes, validationInfo));
        }

        public static MvcForm BeginValidatedForm(this HtmlHelper htmlHelper)
        {
            var formAction = htmlHelper.ViewContext.HttpContext.Request.RawUrl;
            return htmlHelper.BeginForm("", "", FormMethod.Post, GetFormValidationAttributes(new { action = formAction }));
        }

        public static MvcForm BeginValidatedForm(this HtmlHelper htmlHelper, string actionName, string controllerName)
        {
            return htmlHelper.BeginForm(actionName, controllerName, FormMethod.Post, GetFormValidationAttributes());
        }

        public static MvcForm BeginValidatedForm(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
        {
            return htmlHelper.BeginForm(actionName, controllerName, routeValues, method, GetFormValidationAttributes(htmlAttributes));
        }

        public static MvcForm BeginValidatedForm(this HtmlHelper htmlHelper, object routeValues)
        {
            return htmlHelper.BeginForm(null, null, routeValues, FormMethod.Post, GetFormValidationAttributes());
        }

        private static IDictionary<string, object> GetFormValidationAttributes()
        {
            return GetFormValidationAttributes(null);
        }

        private static IDictionary<string, object> GetFormValidationAttributes(object htmlAttributes)
        {
            var attributes = (null == htmlAttributes) ? new Dictionary<string, object>() : GetHtmlAttributes(htmlAttributes);
            attributes.Add("onsubmit", "return validateForm();");
            return attributes;
        }

        private static Dictionary<string, object> GetValidationAttributes(Validation valInfo)
        {
            return GetValidationAttributes(null, valInfo);
        }

        private static Dictionary<string, object> GetValidationAttributes(object htmlAttributes, Validation valInfo)
        {
            Dictionary<string, object> attr = (null == htmlAttributes) ? new Dictionary<string, object>() : GetHtmlAttributes(htmlAttributes);
            valInfo.SetAttributes(attr);
            return attr;
        }

        private static Dictionary<string, object> GetHtmlAttributes(object htmlAttributes)
        {
            var htmlAttr = new Dictionary<string, object>();
            var props = htmlAttributes.GetType().GetProperties();
            foreach (var prop in props) htmlAttr.Add(prop.Name.ToLower(), prop.GetValue(htmlAttributes, null));
            return htmlAttr;
        }

        public static string CheckBoxList(this HtmlHelper htmlHelper, string name, List<CheckBoxListInfo> listInfo,

            IDictionary<string, object> htmlAttributes)
        {
            if (String.IsNullOrEmpty(name))
                throw new ArgumentException("The argument must have a value", "name");

            if (listInfo == null)
                throw new ArgumentNullException("listInfo");

            //if (listInfo.Count < 1)
            //    throw new ArgumentException("The list must contain at least one value", "listInfo");

            StringBuilder sb = new StringBuilder();
            foreach (CheckBoxListInfo info in listInfo)
            {
                TagBuilder builder = new TagBuilder("input");
                if (info.IsChecked) builder.MergeAttribute("checked", "checked");
                builder.MergeAttributes<string, object>(htmlAttributes);
                builder.MergeAttribute("type", "checkbox");
                builder.MergeAttribute("value", info.Value);
                builder.MergeAttribute("name", name);
                builder.InnerHtml = info.DisplayText;
                sb.Append(builder.ToString(TagRenderMode.Normal));
                sb.Append("<br />");

            }
            return sb.ToString();
        }
    }

    // This the information that is needed by each checkbox in the
    // CheckBoxList helper.
    public class CheckBoxListInfo
    {
        public CheckBoxListInfo(string value, string displayText, bool isChecked)
        {

            this.Value = value;

            this.DisplayText = displayText;

            this.IsChecked = isChecked;

        }

        public string Value { get; private set; }
        public string DisplayText { get; private set; }
        public bool IsChecked { get; private set; }
    }
}
